package learn_concurrent._11;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

public class CASBigDecimalAccountTest {
	
	public static void main(String[] args) {
		BigDecimalAccount.demo(new CASBigDecimalAccount(BigDecimal.valueOf(10000)));
	}
	
}

class CASBigDecimalAccount implements BigDecimalAccount {

    private AtomicReference<BigDecimal> balance;

    public CASBigDecimalAccount(BigDecimal balance) {
        this.balance = new AtomicReference<>(balance);
    }

    @Override
    public BigDecimal getBalance() {
        return balance.get();
    }

    @Override
    public void withdraw(BigDecimal amount) {
        while(true) {
        	BigDecimal prev = balance.get();
        	BigDecimal next = prev.subtract(amount);
        	if(balance.compareAndSet(prev, next)) {
        		break;
        	}
        }
    }
}

interface BigDecimalAccount {
    BigDecimal getBalance();

    void withdraw(BigDecimal amount);

    static void demo(BigDecimalAccount account) {
        List<Thread> threadList = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            threadList.add(new Thread(() -> account.withdraw(BigDecimal.TEN)));
        }

        long start = System.nanoTime();
        threadList.forEach(Thread::start);
        threadList.forEach(thread -> {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        long end = System.nanoTime();
        System.out.println(account.getBalance() + " cost:" + (end - start) / 1000_000 + "ms");
    }
}
